package assemblerNG;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

public class Assembler {
	
	protected final String REND_SWITCH = "0101";
	protected final String MEM_LE = "0";
	protected final String MEM_ESCREVE = "1";
	
	Microinstruction micro = new Microinstruction();
	AnythingToBin anyToBin = new AnythingToBin();

	ArrayList<String> bin = new ArrayList<String>();
	
	String operTemp, origTemp, destTemp;

	
	public ArrayList<String> assembly(ArrayList<String> asm){
		
		asm.add("MOVE <#40, R0>");
		asm.add("MOVE <R0, R1>");
		asm.add("HALT");
		
		String temp;
		ArrayList<String> result;
		
		Iterator it = asm.iterator();
		while (it.hasNext()) {
			temp = null;
			result = null;
			temp = (String) it.next();
			result = translate(temp);
			bin.addAll(result);
		}			
		
		return bin;
	}


	private ArrayList<String> translate(String temp) {
		destTemp = null;
		origTemp = null;
		operTemp = null;
		ArrayList<String> output = new ArrayList<String>();
		String[] operands;
		int quantidade;
		boolean destReferenciado = false;
		boolean origReferenciado = false;
		boolean destConstante = false;
		boolean origConstante = false;
		
		operands = temp.split(" ");
		for (int i = 0; i < operands.length; i++) {
			operands[i] = operands[i].trim();
		}
		if (operands.length == 2 || operands.length == 3) {
			if (operands[1].startsWith("["))
				origReferenciado = true;
			else if (operands[1].startsWith("#"))
				origConstante = true;
			origTemp = operands[1];
		}
		if (operands.length == 3) {
			if (operands[2].startsWith("["))
				destReferenciado = true;
			else if (operands[2].startsWith("#"))
				destConstante = true;
			destTemp = operands[2];
		}
		operTemp = operands[0];
		quantidade = operands.length;
		output.addAll(opcodify(operTemp, origTemp, destTemp, origReferenciado, origConstante, destReferenciado, destConstante, quantidade));		
		micro.flushMicro();
				
		return output;
	}


	private ArrayList<String> opcodify(String operando, String origem, String destino, boolean origReferenciado, boolean origConstante, boolean destReferenciado, boolean destConstante, int quantidade) {
		ArrayList<String> opcode = new ArrayList<String>();
		operando = operando.trim();
		if (quantidade == 2) {
			origem = origem.trim();
			if (origReferenciado) {
				origem = String.valueOf(origem.subSequence(1, origem.length()-2));
			}
			if (origConstante) {
				origem = String.valueOf(origem.subSequence(1, origem.length()-1));
				origem = anyToBin.anythingToBin(origem);
			}
			
		}// else eh Rx,
		if (quantidade == 3) {
			origem = origem.trim();
			if (origReferenciado) {//[Rx]
				origem = String.valueOf(origem.subSequence(1, origem.length()-3));
			}
			if (origConstante) {//#32 #0x29
				origem = String.valueOf(origem.subSequence(1, origem.length()-2));
				origem = anyToBin.anythingToBin(origem);
			}
			
			destino = destino.trim();
			if (destReferenciado) {
				destino = String.valueOf(destino.subSequence(1, destino.length()-2));
			}
			if (destConstante) {
				destino = String.valueOf(destino.subSequence(1, destino.length()-1));
				destino = anyToBin.anythingToBin(destino);
			}
		}// else eh Rx puro
		
		if (origem.startsWith("r0") || origem.startsWith("R0"))
			origem = "000";
		if (origem.startsWith("r1") || origem.startsWith("R1"))
			origem = "001";
		if (origem.startsWith("r2") || origem.startsWith("R2"))
			origem = "010";
		if (origem.startsWith("r3") || origem.startsWith("R3"))
			origem = "011";
		if (origem.startsWith("r4") || origem.startsWith("R4"))
			origem = "100";
		
		if (destino.equalsIgnoreCase("R0"))
			destino = "000";
		if (destino.equalsIgnoreCase("R1"))
			destino = "001";
		if (destino.equalsIgnoreCase("R2"))
			destino = "010";
		if (destino.equalsIgnoreCase("R3"))
			destino = "011";
		if (destino.equalsIgnoreCase("R4"))
			destino = "100";
	
		if (operando.equalsIgnoreCase("move")) {
			if (origReferenciado) {
				micro.setaAddr(origem);
				micro.setbAddr(origem);
				micro.setAluOp("0101");
				micro.setSwitchPos(REND_SWITCH);
				micro.setcAddr("000");
				micro.setMemWrite("MEM_LE");
				micro.setDirectOperand("00000000");
				//deixa em REnd quem esta na [origem]
				opcode.add(micro.getMicro());
				micro.setSwitchPos("1010");
				micro.setcAddr(destino);
				opcode.add(micro.getMicro());
			} else if (destReferenciado) {
				micro.setaAddr(origem);
				micro.setbAddr(origem);
				micro.setAluOp("0101");
				micro.setSwitchPos(REND_SWITCH);
				micro.setcAddr("000");
				micro.setMemWrite("MEM_LE");
				micro.setDirectOperand("00000000");
				//deixa em REnd quem esta na [origem]
				opcode.add(micro.getMicro());
			}
			
			micro.setaAddr("000");
			micro.setbAddr("000");
			micro.setAluOp("0101");
			micro.setSwitchPos("1001");
			micro.setcAddr(destino);
			micro.setMemWrite("0");
			micro.setDirectOperand("00000000");
			
			opcode.add(micro.getMicro());
		}
		
		return opcode;
	}

}
